package com.hup.utils.commons.swing;

import com.hup.utils.commons.exception.AppExceptionHandler;
import com.hup.utils.commons.exception.ErrInfo;
import com.hup.utils.commons.interfaces.Runners.RunAndThrowable;
import com.hup.utils.commons.start.DialogHelper;
import com.hup.utils.commons.thread.component.EfficientExecutor;
import sun.awt.AppContext;

import javax.swing.*;
import java.awt.*;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * ui异步执行器基础接口类;
 * <pre>
 *     使用前需要 {@link SwingExecutable#initSwingExecutor()}
 *     和 {@link SwingWorker}是有点相似的,但本类注重的是[仅负责基本的executor功能和异常捕获环节],
 *     {@link SwingWorker}中的进度功能由业务代码管理
 * </pre>
 *
 * @author hugan
 * @date 2020/6/8
 */
public interface SwingExecutable extends ExecuteExceptionHandler {

    /**
     * 初始化 awt的 {@link SwingWorker};
     * <pre>
     * 配置:
     *  常驻线程:1
     *  最大线程:5,注意这是swing共用的最大线程
     *  最大任务数:5+20等待队列
     * </pre>
     *
     * @apiNote SwingWorker会被swing共用于组件功能中, 如: {@link JEditorPane#setPage(URL)}
     */
    static void initSwingExecutor() {
        if (AppContext.getAppContext().get(SwingWorker.class) != null) {
            throw new IllegalArgumentException("SwingWorker已被初始化!?");
        }
        AppContext.getAppContext().put(SwingWorker.class, new EfficientExecutor(
                1, 5,
                20,
                30, TimeUnit.SECONDS,
                "EfficientSwingWorker-",
                "ui异步执行器"));
    }

    default ThreadPoolExecutor getExecutor() {
        ThreadPoolExecutor res = (ThreadPoolExecutor) AppContext.getAppContext().get(SwingWorker.class);
        if (res == null) throw new IllegalArgumentException("未初始化SwingExecutable.initSwingExecutor");
        return res;
    }

    default void runOnUiThread(String desc, Runnable task) {
        SwingUtilities.invokeLater(() -> {
            try {
                task.run();
            } catch (Throwable e) {
                onExecuteException(desc, e);
            }
        });
    }

    default <R> void execute(ExecuteFullTask<R> task) {
        execute(task.getDesc(), task.getExecutor(), task, task, task);
    }

    default <R> void execute(String desc, ExecuteTask<R> asyncTask) {
        execute(desc, getExecutor(), asyncTask, asyncTask, this);
    }

    /**
     * 常用方法
     */
    default <R> void execute(String desc, Callable<R> asyncTask, Consumer<R> resultHandler) {
        execute(desc, getExecutor(), asyncTask, resultHandler, this);
    }

    default <R> void execute(String desc, Callable<R> asyncTask, Consumer<R> resultHandler,
            ExecuteExceptionHandler exceptionHandler) {
        execute(desc, getExecutor(), asyncTask, resultHandler, exceptionHandler);
    }

    default <R> void execute(String desc, ThreadPoolExecutor executor, Callable<R> asyncTask, Consumer<R> resultHandler,
            ExecuteExceptionHandler exceptionHandler) {
        try {
            executor.execute(() -> {
                try {
                    R res = asyncTask.call();
                    SwingUtilities.invokeLater(() -> {
                        try {
                            resultHandler.accept(res);
                        } catch (Throwable e) {
                            exceptionHandler.onExecuteException(desc, e);
                        }
                    });
                } catch (Throwable e) {
                    exceptionHandler.onExecuteException(desc, e);
                }
            });
        } catch (Throwable e) {
            exceptionHandler.onExecuteException(desc, e);
        }
    }

    default void doInBackground(ExecuteFullTask task) {
        doInBackground(task.getDesc(), task.getExecutor(), task, task);
    }

    /**
     * 常用方法
     */
    default void doInBackground(String desc, RunAndThrowable runnable) {
        doInBackground(desc, getExecutor(), runnable, this);
    }

    /**
     * @param desc 任务描述
     */
    default void doInBackground(String desc, ThreadPoolExecutor executor, RunAndThrowable runnable,
            ExecuteExceptionHandler exceptionHandler) {
        try {
            executor.execute(() -> {
                try {
                    runnable.run();
                } catch (Throwable e) {
                    exceptionHandler.onExecuteException(desc, e);
                }
            });
        } catch (Throwable e) {
            exceptionHandler.onExecuteException(desc, e);
        }
    }

    /**
     * 在当前线程执行功能,并捕获异常
     */
    default void runWithCatch(String desc, RunAndThrowable runAndThrowable) {
        try {
            runAndThrowable.run();
        } catch (Throwable e) {
            onExecuteException(desc, e);
        }
    }

    default void onExecuteException(String desc, Throwable e) {
        ErrInfo errInfo = AppExceptionHandler.handle(desc + "错误:\n", e);
        DialogHelper.confirm(errInfo.getErrMsg())
                .title(DialogHelper.ERROR)
                .show((Window) this);
    }

    /**
     * 用于支持[多个返回值]的情况
     *
     * @param <R> 返回的数据
     */
    interface ExecuteTask<R> extends Consumer<R>, Callable<R> {

    }

    /**
     * 覆盖全生命周期的任务[异步执行任务,ui线程处理结果,处理捕获异常]
     *
     * @param <R> 返回的数据
     */
    interface ExecuteFullTask<R> extends RunAndThrowable, ExecuteTask<R>, ExecuteExceptionHandler {

        /**
         * @return 任务描述, 用于 {@link ExecuteExceptionHandler#onExecuteException(String, Throwable)}
         */
        String getDesc();

        /**
         * 指定执行器
         */
        ThreadPoolExecutor getExecutor();

        /**
         * 只在 doInBackground方法时调用
         */
        @Override
        default void run() throws Throwable {}

        /**
         * 只在 execute方法时调用
         */
        @Override
        default R call() throws Exception {
            return null;
        }

        /**
         * 只在 execute方法时调用
         */
        @Override
        default void accept(R r) {}
    }

}
